#include <stdlib.h>
#include <ucontext.h>
#define STACK_SIZE 64*1024
#ifndef THREAD
#define THREAD
typedef enum{/*PROPER_END, ERROR_END,*/ENDED, SLEEPING,RUNNING } thread_status;
struct thread {
	thread_status status;
	ucontext_t context;
	struct timeval* execution_time;
	unsigned int thread_id;
	void* retval;
};
typedef struct thread* thread_t;

/* recuperer l'identifiant du thread courant.
 */

extern thread_t thread_self(void);

/** creer un nouveau thread qui va exécuter la fonction func avec l'argument funcarg.
 *
 * La fonction makecontext() modifie le contexte pointé par ucp (qui a été
 *     obtenu par un appel à getcontext(2)).  Avant  d'appeler  makecontext(),
 *     l'appelant   doit  allouer  une  nouvelle  pile  pour  ce  contexte  et
 *     l'affecter  à  ucp->uc_stack  et  définir  un  contexte  successeur  et
 *     l'affecter à ucp->uc_link.
 *@return renvoie 0 en cas de succès, -1 en cas d'erreur.
 *
 */
extern int thread_create(thread_t* newthread, void *(*func)(void *), void *funcarg);

/** passer la main à un autre thread.
 * @return renvoie 0 en cas de succès,-1 si le changement de contexte n'a pas pu etre fini.
 */
extern int thread_yield();
/** attendre la fin d'exécution d'un thread.
 * @param retval la valeur renvoyée par le thread est placée dans *retval.
 * si retval est NULL, la valeur de retour est ignorée.
 * @param thread thread qui sera attendu par le thread appelant cette fonction
 * @return renvoie 0 en cas de succès, -1 si il y a eu un probleme lors de l'attente ou de la récupération de
 * la valeur de retour
 */
extern int thread_join(thread_t thread, void **retval);
/** terminer le thread courant en renvoyant la valeur de retour retval.
 * cette fonction ne retourne jamais.
 *
 * L'attribut noreturn aide le compilateur à optimiser le code de
 * l'application (élimination de code mort). Attention à ne pas mettre
 * cet attribut dans votre interface tant que votre thread_exit()
 * n'est pas correctement implémenté (il ne doit jamais retourner).
 * @param retval valeur de retour du thread qui va terminer
 */
extern void thread_exit(void *retval) __attribute__ ((__noreturn__));
/**
 * initialise le thread courant et le place sur la runq. Elle permet de gérer le main comme un thread quelconque
 */
void thread_init();
#endif//THREAD
